package com.swingson.properties.specificclass_impl;

import com.swingson.Swingson;
import com.swingson.SwingsonGui;
import com.swingson.jsonparser.JsonElement;
import com.swingson.other.ConditionAndAction;
import com.swingson.other.MethodExecutor;
import com.swingson.properties.AbstractAssignMethodPropertyProcessor;
import java.awt.Component;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JComponent;

/**
 * @author sad
 */
public class FocusListenerPropertyProcessor extends AbstractAssignMethodPropertyProcessor {

    public static final String focusGained = "focusGained";
    public static final String focusLost = "focusLost";

    static List<Class[]> argumentsVariants = new ArrayList<Class[]>() {
        {
            add(new Class[]{});
            add(new Class[]{Component.class});//opposite component
        }
    };

    @Override
    protected String getName() {
        return "Focus Event Listener";
    }

    @Override
    protected List<Class[]> methodArgumentsVariants() {
        return argumentsVariants;
    }

    @Override
    protected void attachMethod(JsonElement jsonElement, final JComponent component, final SwingsonGui gui, String propertyName, final MethodExecutor mExecutor, final int methodArgumentVariant, final ConditionAndAction conditionAndAction) {
        EventExecutor<FocusEvent> executor = new EventExecutor<FocusEvent>() {
            @Override
            public void execute(FocusEvent event) {
                if (!Swingson.isEnabledUserInput()) {
                    return;
                }
                try {
                    switch (methodArgumentVariant) {
                        case 0:
                            mExecutor.invoke(event.getOppositeComponent());
                            break;
                        case 1:
                            mExecutor.invoke(event.getOppositeComponent());
                            break;
                    }
                    runAction(conditionAndAction, gui, component);
                } catch (Throwable ex) {
                    onError(gui, ex);
                }
            }
        };
        for (FocusListener listener : component.getFocusListeners()) {
            if (listener instanceof FocusListenerWrapper) {
                FocusListenerWrapper lw = (FocusListenerWrapper) listener;
                switch (propertyName) {
                    case focusGained:
                        lw.setFocusGained(executor);
                        break;
                    case focusLost:
                        lw.setFocusLost(executor);
                        break;
                }
                return;
            }
        }

        FocusListenerWrapper listener = new FocusListenerWrapper();
        switch (propertyName) {
            case focusGained:
                listener.setFocusGained(executor);
                break;
            case focusLost:
                listener.setFocusLost(executor);
                break;
        }

        component.addFocusListener(listener);
    }

    private static class FocusListenerWrapper implements FocusListener {

        private EventExecutor<FocusEvent> focusGained;
        private EventExecutor<FocusEvent> focusLost;

        public void setFocusGained(EventExecutor<FocusEvent> focusGained) {
            this.focusGained = focusGained;
        }

        public void setFocusLost(EventExecutor<FocusEvent> focusLost) {
            this.focusLost = focusLost;
        }

        @Override
        public void focusGained(FocusEvent e) {
            if (focusGained != null) {
                focusGained.execute(e);
            }
        }

        @Override
        public void focusLost(FocusEvent e) {
            if (focusLost != null) {
                focusLost.execute(e);
            }
        }
    }
}
